iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0

專案起始的開發順序與檢查

曾經我在資料夾開好 laravel 專案後,一時不知道從哪裡下手……所以後來我大概都依照下面順序進行,不過每個人不同,下面順序也不一定是上下有相關,可以參考參考就好XD

  1. .env 編輯

  2. 參考 ER Diagram 編輯 migration、定義各欄位結構

  3. 測試:

    • php artisan migrate 看執行是否報錯,沒有報錯的話代表.env內容也都正確
    • 用 table plus 看資料表有沒有正常被新增
    • php artisan migrate:rollback 看執行是否報錯
    • 用 table plus 看資料表有沒有正常被刪除或回復 →這點非常重要!!

    如果有異動 migration,務必執行看看、也測試看看 rollback,只執行migrate而忽略 rollback的話,rollback 錯誤是不會顯示出來的!

  4. 編輯 model 檔案

  5. 建立 routes, controller, view 或處理回覆的 resource, collection 等檔案

今日目標

依照上面的開發順序,昨天大概是進行到第三點結束,還沒有編輯 Model 檔案,所以今日要來進行 Model 檔案編輯,並用 Seeder 建立資料。

https://ithelp.ithome.com.tw/upload/images/20230928/20162893rDMx6yiFGH.png

每個主要功能其實就如同上圖,不外乎 index, create, store, show, edit, update, destroy 七種功能。今天我們就來嘗試用 團購 Group 建立其中的三種功能 index, show, destroy 吧!

備註:這七種功能的稱呼方式可以說是工程師彼此間溝通的術語,講 index 大家就知道你說的功能是什麼,所以可以儘早熟悉一下,也是我做這張圖的目的。

以後端角度來做 Group 的 index, show, destroy 功能

Group Model

檔案路徑:app/Models/Group.php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Group extends Model
{
    use HasFactory;

    const STATUS_NOT_STARTED = 0; // 未開團
    const STATUS_OPEN = 1; // 開團中
    const STATUS_CLOSE = 2; // 結團處理中
    const STATUS_DELIVERED = 3; // 運送取貨中

    protected $fillable = [
        'id',
        'group_name',
        'organizer_id',
        'close_price',
        'close_date',
        'allow_insert_product',
        'status',
    ];

    protected $casts = [
        'created_at' => 'datetime:Y-m-d H:i:s',
        'updated_at' => 'datetime:Y-m-d H:i:s',
    ];
}

一般基本的 Model 檔案大概分成幾個區塊:

https://ithelp.ithome.com.tw/upload/images/20230928/2016289374FKQcq2Ky.png

$fillable & $guarded

$fillable & $guarded 就像白名單與黑名單之間的關係。

  • $fillable 屬性用於定義哪些模型的屬性可以被大量賦值(Mass Assigned)。只有在 $fillable 中列出的屬性才能夠被大量賦值,其他屬性將被自動保護(Guarded)。
  • $guarded 屬性用於定義哪些模型的屬性應該受到保護,不允許大量賦值。只有列在 $guarded 中的屬性會被保護,其他屬性可以被大量賦值。

通常這兩個會擇一使用,我自己在專案中都是使用 $fillable,而且多是從 migration 把欄位名稱直接複製過來修改。

const 常數

很多時候資料表裡面會有 狀態 status, 性別sex, 分類等欄位,這些欄位常用 0~9 這些整數代表不同的意思,例如:0 = 未開團、1 = 開團中等狀態,這個邏輯可能是前後端一起討論出來一起定義的,所以可能會在程式碼的任何地方用到。

菜鳥提問:幹嘛不直接存 “open”、”close”這種字,還要用數字代替?
欄位少的話的確可以,也有資料庫使用偏好存英文字在裡面的,我自己是覺得 數字比英文來得比較明顯正確或錯誤,資料庫搜尋每個欄位的值所消耗的時間或動所也比較少跟簡單。

為了後續維護時,0 需要改成「關閉中」,進而衍生出你要在整個專案中搜尋所有用到的地方然後修改這種麻煩事,我們會在專案裡面以常數的方式定義,屆時只要修改 Model 裡面即可。

// model 裡面定義
const STATUS_NOT_STARTED = 0; // 未開團
const STATUS_OPEN = 1; // 開團中
const STATUS_CLOSE = 2; // 結團處理中
const STATUS_DELIVERED = 3; // 運送取貨中

// controller 裡面使用
Group::where('status', STATUS_OPEN)->get();

其他優點包括:

  1. 資料庫狀態映射: 可以在模型中使用這些常數,以便將數據庫中的整數狀態值映射到更具語義的常數名稱。例如,數據庫中的 status 欄位的值可以是 0、1、2 或 3,但在代碼中,可以使用常數 STATUS_NOT_STARTED 來表示未開團的狀態。
  2. 程式邏輯可讀性: 使用這些常數可以使代碼更具可讀性。當在代碼中看到 STATUS_OPEN 時,立即知道它表示一個開團中的狀態,而不需要記住或查閱數字代碼的含義。
  3. 易於維護和更改: 如果需要更改狀態的值或添加新的狀態,只需更新這些常數的定義,而不需要在代碼的多個地方進行更改。這提高了代碼的可維護性。
  4. 避免硬編碼: 使用這些常數可以避免硬編碼數字或文字值,降低代碼中的硬編碼風險。

GroupSeeder

如同昨天所說,為了避免一直重複資料,所以我先建了 seeder 檔案,讓我們等一下要開發的功能可以取得資料

namespace Database\Seeders;

use App\Models\Group;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class GroupSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
		DB::table('groups')->truncate();          
            // 先刪除所有資料,避免操作中有很多重複的麥當勞XD

        DB::table('groups')->insert([
            'group_name'           => '麥當勞',
            'organizer_id'         => rand(1, 3),
            'close_price'          => 1000,
            'close_date'           => null,
            'allow_insert_product' => true,
            'status'               => Group::STATUS_OPEN,  
                // 取用剛剛 model 定義的常數
            'created_at'           => now(),
            'updated_at'           => now(),
        ]);

        DB::table('groups')->insert([
            'group_name'           => '肯德基',
            'organizer_id'         => rand(1, 3),
            'close_price'          => 1000,
            'close_date'           => null,
            'allow_insert_product' => true,
            'status'               => Group::STATUS_OPEN,
            'created_at'           => now(),
            'updated_at'           => now(),
        ]);

        DB::table('groups')->insert([
            'group_name'           => fake()->company,   
                // 使用 fake() 產生隨機資料
            'organizer_id'         => rand(1, 3),
            'close_price'          => 1000,
            'close_date'           => null,
            'allow_insert_product' => true,
            'status'               => Group::STATUS_OPEN,
            'created_at'           => now(),
            'updated_at'           => now(),
        ]);
    }
}

seeder 的官方文件還算滿簡單好懂,這邊就不多介紹。

truncate() 清除 table 裡面的所有資料

除了官方文件所教,可以一筆一筆產生資料外,實務開發上也會加入一些判斷式,例如:

  • 如果沒有哪些資料的話才執行 seeder 內容
  • 或 把所有資料先全部刪除,再執行 seeder 內容

因此這裡我用了 truncate() ,即使資料表裡面已經有資料,我還是先把所有資料刪除,然後執行 seeder,才不會在測試 seeder 內容時看到好多好多麥當勞~

faker 套件中文化

官方文件:https://fakerphp.github.io

Laravel 內建有使用 faker 套件,可快速產生一些 firstName, address, text 等等資料

需要的時候可以用 fake() 函式,參考官方文件也可找到

如果要讓 fake() 產生的假資料為中文,要到 config/app.php 把下面這行改成 zh_TW

// 預設
'faker_locale' => 'en_US',

// 中文化
'faker_locale' => 'zh_TW',

上一篇
Migration & Table Plus 工具 (2)
下一篇
專案筆記:Controller index, show, destroy 功能、paginate分頁
系列文
Laravel 後端菜鳥可以知道的流程概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言